home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / OldSrc / CH11 / SRC / OBJPLIN1.CLS < prev    next >
Text File  |  1996-05-04  |  12KB  |  446 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4. END
  5. Attribute VB_Name = "ObjPolyline"
  6. Attribute VB_Creatable = False
  7. Attribute VB_Exposed = False
  8. Option Explicit
  9.  
  10. ' Point3D and Segment3D are defined in module M3OPS.BAS as:
  11. '    Type Point3D
  12. '        coord(1 To 4) As Single
  13. '        trans(1 To 4) As Single
  14. '    End Type
  15. '
  16. '    Type Segment3D
  17. '        pt1 As Integer
  18. '        pt2 As Integer
  19. '    End Type
  20.  
  21. Private NumPoints As Integer ' Number of points.
  22. Private Points() As Point3D  ' Data points.
  23.  
  24. Private NumSegs As Integer   ' Number of segments.
  25. Private Segs() As Segment3D  ' The segments.
  26.  
  27. Private IsCulled As Boolean
  28.  
  29. ' ***********************************************
  30. ' This is done at drawing time for polylines.
  31. ' ***********************************************
  32. Public Sub ClipEye(r As Single)
  33. End Sub
  34.  
  35.  
  36. ' ***********************************************
  37. ' Return the maximum transformed Z value for this
  38. ' object.
  39. ' ***********************************************
  40. Property Get zmax() As Single
  41. Dim best As Single
  42. Dim z As Single
  43. Dim i As Integer
  44.  
  45.     best = Points(1).trans(3)
  46.     For i = 2 To NumPoints
  47.         z = Points(i).trans(3)
  48.         If best < z Then best = z
  49.     Next i
  50.     zmax = best
  51. End Property
  52.  
  53.  
  54.  
  55. Sub Stellate(L As Single, ParamArray coord() As Variant)
  56. Dim x0 As Single
  57. Dim y0 As Single
  58. Dim z0 As Single
  59. Dim x1 As Single
  60. Dim y1 As Single
  61. Dim z1 As Single
  62. Dim x2 As Single
  63. Dim y2 As Single
  64. Dim z2 As Single
  65. Dim x3 As Single
  66. Dim y3 As Single
  67. Dim z3 As Single
  68. Dim Ax As Single
  69. Dim Ay As Single
  70. Dim Az As Single
  71. Dim Bx As Single
  72. Dim By As Single
  73. Dim Bz As Single
  74. Dim nx As Single
  75. Dim ny As Single
  76. Dim nz As Single
  77. Dim num As Integer
  78. Dim i As Integer
  79. Dim pt As Integer
  80.  
  81.     num = (UBound(coord) + 1) \ 3
  82.     If num < 3 Then
  83.         Beep
  84.         MsgBox "Must have at least 3 points to stellate.", , vbExclamation
  85.         Exit Sub
  86.     End If
  87.     
  88.     ' (x0, y0, z0) is the center of the polygon.
  89.     x0 = 0
  90.     y0 = 0
  91.     z0 = 0
  92.     pt = 0
  93.     For i = 1 To num
  94.         x0 = x0 + coord(pt)
  95.         y0 = y0 + coord(pt + 1)
  96.         z0 = z0 + coord(pt + 2)
  97.         pt = pt + 3
  98.     Next i
  99.     x0 = x0 / num
  100.     y0 = y0 / num
  101.     z0 = z0 / num
  102.     
  103.     ' Find the normal.
  104.     x1 = coord(0)
  105.     y1 = coord(1)
  106.     z1 = coord(2)
  107.     x2 = coord(3)
  108.     y2 = coord(4)
  109.     z2 = coord(5)
  110.     x3 = coord(6)
  111.     y3 = coord(7)
  112.     z3 = coord(8)
  113.     Ax = x2 - x1
  114.     Ay = y2 - y1
  115.     Az = z2 - z1
  116.     Bx = x3 - x2
  117.     By = y3 - y2
  118.     Bz = z3 - z2
  119.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  120.     
  121.     ' Give the normal length L.
  122.     m3SizeVector L, nx, ny, nz
  123.     
  124.     ' The normal + <x0, y0, z0> gives the point.
  125.     x0 = x0 + nx
  126.     y0 = y0 + ny
  127.     z0 = z0 + nz
  128.  
  129.     ' Build the segments that make up the object.
  130.     x1 = coord(3 * num - 3)
  131.     y1 = coord(3 * num - 2)
  132.     z1 = coord(3 * num - 1)
  133.     pt = 0
  134.     For i = 1 To num
  135.         x2 = coord(pt)
  136.         y2 = coord(pt + 1)
  137.         z2 = coord(pt + 2)
  138.         AddSegment x1, y1, z1, x2, y2, z2, x0, y0, z0
  139.         x1 = x2
  140.         y1 = y2
  141.         z1 = z2
  142.         pt = pt + 3
  143.     Next i
  144. End Sub
  145.  
  146. Sub CreateNormal(Objects As Collection)
  147. Dim pline As New ObjPolyline
  148. Dim x1 As Single
  149. Dim y1 As Single
  150. Dim z1 As Single
  151. Dim x2 As Single
  152. Dim y2 As Single
  153. Dim z2 As Single
  154.  
  155.     Objects.Add pline
  156.     UnitNormalSegment x1, y1, z1, x2, y2, z2
  157.     pline.AddSegment x1, y1, z1, x2, y2, z2
  158. End Sub
  159.  
  160.  
  161. ' ***********************************************
  162. ' Compute a normal vector for this polyline.
  163. ' ***********************************************
  164. Sub NormalVector(nx As Single, ny As Single, nz As Single)
  165. Dim Ax As Single
  166. Dim Ay As Single
  167. Dim Az As Single
  168. Dim Bx As Single
  169. Dim By As Single
  170. Dim Bz As Single
  171.  
  172.     Ax = Points(2).coord(1) - Points(1).coord(1)
  173.     Ay = Points(2).coord(2) - Points(1).coord(2)
  174.     Az = Points(2).coord(3) - Points(1).coord(3)
  175.     Bx = Points(3).coord(1) - Points(2).coord(1)
  176.     By = Points(3).coord(2) - Points(2).coord(2)
  177.     Bz = Points(3).coord(3) - Points(2).coord(3)
  178.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  179. End Sub
  180.  
  181.  
  182.  
  183. ' ***********************************************
  184. ' Compute the unit normal line segment for this
  185. ' polyline.
  186. ' ***********************************************
  187. Sub UnitNormalSegment(x1 As Single, y1 As Single, z1 As Single, x2 As Single, y2 As Single, z2 As Single)
  188. Dim i As Integer
  189. Dim nx As Single
  190. Dim ny As Single
  191. Dim nz As Single
  192.     
  193.     UnitNormalVector nx, ny, nz
  194.     
  195.     x1 = 0
  196.     y1 = 0
  197.     z1 = 0
  198.     For i = 1 To NumPoints
  199.         x1 = x1 + Points(i).coord(1)
  200.         y1 = y1 + Points(i).coord(2)
  201.         z1 = z1 + Points(i).coord(3)
  202.     Next i
  203.     x1 = x1 / NumPoints
  204.     y1 = y1 / NumPoints
  205.     z1 = z1 / NumPoints
  206.  
  207.     x2 = x1 + nx
  208.     y2 = y1 + ny
  209.     z2 = z1 + nz
  210. End Sub
  211.  
  212.  
  213. ' ***********************************************
  214. ' Compute the unit normal vector for this
  215. ' polyline.
  216. ' ***********************************************
  217. Sub UnitNormalVector(nx As Single, ny As Single, nz As Single)
  218. Dim D As Single
  219.  
  220.     NormalVector nx, ny, nz
  221.     D = Sqr(nx * nx + ny * ny + nz * nz)
  222.     nx = nx / D
  223.     ny = ny / D
  224.     nz = nz / D
  225. End Sub
  226.  
  227.  
  228.  
  229.  
  230.  
  231. Property Let Culled(value As Boolean)
  232.     IsCulled = value
  233. End Property
  234.  
  235.  
  236. ' ***********************************************
  237. ' Return a string indicating the object type.
  238. ' ***********************************************
  239. Property Get ObjectType() As String
  240.     ObjectType = "POLYLINE"
  241. End Property
  242.  
  243. ' ************************************************
  244. ' Add one or more line segments to the polyline.
  245. ' ************************************************
  246. Public Sub AddSegment(ParamArray coord() As Variant)
  247. Dim num_segs As Integer
  248. Dim i As Integer
  249. Dim last As Integer
  250. Dim pt As Integer
  251.  
  252.     num_segs = (UBound(coord) + 1) \ 3 - 1
  253.     ReDim Preserve Segs(1 To NumSegs + num_segs)
  254.  
  255.     last = AddPoint((coord(0)), (coord(1)), (coord(2)))
  256.     pt = 0
  257.     For i = 1 To num_segs
  258.         Segs(NumSegs + i).pt1 = last
  259.         pt = pt + 3
  260.         last = AddPoint((coord(pt)), (coord(pt + 1)), (coord(pt + 2)))
  261.         Segs(NumSegs + i).pt2 = last
  262.     Next i
  263.  
  264.     NumSegs = NumSegs + num_segs
  265. End Sub
  266.  
  267. ' ************************************************
  268. ' Add a point to the polyline. Return the point's
  269. ' index.
  270. ' ************************************************
  271. Private Function AddPoint(X As Single, Y As Single, z As Single) As Integer
  272. Dim i As Integer
  273.  
  274.     ' See if the point is already here.
  275.     For i = 1 To NumPoints
  276.         If X = Points(i).coord(1) And _
  277.            Y = Points(i).coord(2) And _
  278.            z = Points(i).coord(3) Then _
  279.                 Exit For
  280.     Next i
  281.     AddPoint = i
  282.     
  283.     ' If so, we're done.
  284.     If i <= NumPoints Then Exit Function
  285.     
  286.     ' Otherwise create the new point.
  287.     NumPoints = NumPoints + 1
  288.     ReDim Preserve Points(1 To NumPoints)
  289.     Points(i).coord(1) = X
  290.     Points(i).coord(2) = Y
  291.     Points(i).coord(3) = z
  292.     Points(i).coord(4) = 1#
  293. End Function
  294.  
  295.  
  296. ' ***********************************************
  297. ' Fix the data coordinates at their transformed
  298. ' values.
  299. ' ***********************************************
  300. Public Sub FixPoints()
  301. Dim i As Integer
  302. Dim j As Integer
  303.  
  304.     For i = 1 To NumPoints
  305.         For j = 1 To 3
  306.             Points(i).coord(j) = Points(i).trans(j)
  307.         Next j
  308.     Next i
  309. End Sub
  310.  
  311. ' ************************************************
  312. ' Apply a transformation matrix which may not
  313. ' contain 0, 0, 0, 1 in the last column to the
  314. ' object.
  315. ' ************************************************
  316. Public Sub ApplyFull(M() As Single)
  317. Dim i As Integer
  318.  
  319.     If IsCulled Then Exit Sub
  320.     For i = 1 To NumPoints
  321.         m3ApplyFull Points(i).coord, M, Points(i).trans
  322.     Next i
  323. End Sub
  324.  
  325. ' ************************************************
  326. ' Apply a transformation matrix to the object.
  327. ' ************************************************
  328. Public Sub Apply(M() As Single)
  329. Dim i As Integer
  330.  
  331.     If IsCulled Then Exit Sub
  332.     For i = 1 To NumPoints
  333.         m3Apply Points(i).coord, M, Points(i).trans
  334.     Next i
  335. End Sub
  336.  
  337.  
  338. ' ************************************************
  339. ' Apply a nonlinear transformation.
  340. ' ************************************************
  341. Public Sub Distort(D As Object)
  342. Dim i As Integer
  343.  
  344.     For i = 1 To NumPoints
  345.         D.Distort Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  346.     Next i
  347. End Sub
  348.  
  349. ' ************************************************
  350. ' Write a polyline to a file using Write.
  351. ' Begin with "POLYLINE" to identify this object.
  352. ' ************************************************
  353. Public Sub FileWrite(filenum As Integer)
  354. Dim i As Integer
  355.  
  356.     Write #filenum, "POLYLINE", NumPoints, NumSegs
  357.     
  358.     ' Write the points.
  359.     For i = 1 To NumPoints
  360.         Write #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  361.     Next i
  362.  
  363.     ' Write the segments.
  364.     For i = 1 To NumSegs
  365.         Write #filenum, Segs(i).pt1, Segs(i).pt2
  366.     Next i
  367. End Sub
  368.  
  369. ' ************************************************
  370. ' Draw the transformed points on a Form, Printer,
  371. ' or PictureBox.
  372. ' ************************************************
  373. Public Sub Draw(canvas As Object, Optional r As Variant)
  374. Dim seg As Integer
  375. Dim pt1 As Integer
  376. Dim pt2 As Integer
  377. Dim dist As Single
  378.  
  379.     ' Don't draw if culled.
  380.     If IsCulled Then Exit Sub
  381.     
  382.     On Error Resume Next
  383.     If IsMissing(r) Then r = INFINITY
  384.     dist = r
  385.     For seg = 1 To NumSegs
  386.         pt1 = Segs(seg).pt1
  387.         pt2 = Segs(seg).pt2
  388.         ' Don't draw if either point is farther
  389.         ' from the focus point than the center of
  390.         ' projection (which is distance dist away).
  391.         If Points(pt1).trans(3) < dist And _
  392.            Points(pt2).trans(3) < dist Then _
  393.                 canvas.Line _
  394.                     (Points(pt1).trans(1), Points(pt1).trans(2))- _
  395.                     (Points(pt2).trans(1), Points(pt2).trans(2))
  396.     Next seg
  397. End Sub
  398. ' ***********************************************
  399. ' Perform backface removal.
  400. ' ***********************************************
  401. Public Sub Cull(X As Single, Y As Single, z As Single)
  402. Dim Ax As Single
  403. Dim Ay As Single
  404. Dim Az As Single
  405. Dim nx As Single
  406. Dim ny As Single
  407. Dim nz As Single
  408.  
  409.     ' Compute a normal to the face.
  410.     NormalVector nx, ny, nz
  411.  
  412.     ' Compute a vector from the center of
  413.     ' projection to the face.
  414.     Ax = Points(1).coord(1) - X
  415.     Ay = Points(1).coord(2) - Y
  416.     Az = Points(1).coord(3) - z
  417.     
  418.     ' See if the vectors meet at an angle < 90.
  419.     IsCulled = (Ax * nx + Ay * ny + Az * nz >= 0)
  420. End Sub
  421. ' ************************************************
  422. ' Read a polyline from a file using Input.
  423. ' Assume the "POLYLINE" label has already been
  424. ' read.
  425. ' ************************************************
  426. Public Sub FileInput(filenum As Integer)
  427. Dim i As Integer
  428.  
  429.     Input #filenum, NumPoints, NumSegs
  430.     
  431.     ' Allocate and read the points.
  432.     ReDim Points(1 To NumPoints)
  433.     For i = 1 To NumPoints
  434.         Input #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  435.         Points(i).coord(4) = 1
  436.     Next i
  437.     
  438.     ' Allocate and read the segments.
  439.     ReDim Segs(1 To NumSegs)
  440.     For i = 1 To NumSegs
  441.         Input #filenum, Segs(i).pt1, Segs(i).pt2
  442.     Next i
  443. End Sub
  444.  
  445.  
  446.